package com.checkchan.ethshare.service.share;

import com.checkchan.ethshare.contract.ShareContract;
import com.checkchan.ethshare.model.AccountInfo;
import com.checkchan.ethshare.model.ConfereeInfo;
import com.checkchan.ethshare.model.ShareModel;
import com.checkchan.ethshare.util.Web3jClient;
import org.springframework.stereotype.Service;
import org.web3j.abi.datatypes.Type;
import org.web3j.crypto.CipherException;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.utils.Convert;

import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Service
public class ShareServiceImp implements ShareService {

    private ShareContract contract;
    private static Web3j web3j = Web3jClient.getClient();

    String sourcePassword = "0b60056ce92577506252cddce1b22a4cde6649b0d6805be64b0e1bf97e0d9ebe";
    String constractAddress = "0x6179071c6f8751f8abb7c1946522f2d26bcd7fc3";
    BigInteger GAS_PRICE = BigInteger.valueOf(20_000_000_000L);
    BigInteger GAS_LIMIT = BigInteger.valueOf(4_300_000L);

    public ShareServiceImp() throws IOException,CipherException{

        Credentials credentials = Credentials.create(sourcePassword);
        contract = ShareContract.load(constractAddress,web3j,credentials,GAS_PRICE,GAS_LIMIT);
    }

    public ShareServiceImp(String password) throws IOException,CipherException{
        Credentials credentials = Credentials.create(password);
        contract = ShareContract.load(constractAddress,web3j,credentials,GAS_PRICE,GAS_LIMIT);
    }

    @Override
    public int getShareCount() {
        int res = 0;
        try {
            res = contract.getShareCount().send().getValue().intValue();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return res;
    }

    @Override
    public List<ShareModel> getShares(int pageIndex, int pageSize) {
        List<ShareModel> shares = new ArrayList<ShareModel>();

        try {
            int count = contract.getShareCount().send().getValue().intValue();
            int from = pageIndex * pageSize;
            int to = Math.min((pageIndex + 1) * pageSize, count);
            for(int shareIndex = from; shareIndex < to;shareIndex++){
                List<Type> shareInfo = contract.getShareInfo(shareIndex).send();
                ShareModel share = new ShareModel();

                share.setShareIndex(shareIndex);
                share.setSharer(shareInfo.get(0).toString());
                share.setDesc(shareInfo.get(1).toString());
                share.setScore(new BigInteger(shareInfo.get(2).getValue().toString()).divide(Convert.Unit.ETHER.getWeiFactor().toBigInteger()).intValue());
                share.setConfereeCounts(Integer.parseInt(shareInfo.get(3).getValue().toString()));
                shares.add(share);
            }

            Collections.reverse(shares);
            return shares;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public List<ConfereeInfo> getConfereeInfo(int shareIndex) {
        List<ConfereeInfo> conferees = new ArrayList<ConfereeInfo>();

        try {
            int count = contract.getConfereeCount(shareIndex).send().getValue().intValue();
            for(int confereeIndex = 0; confereeIndex < count;confereeIndex++){
                List<Type> confereeInfo = contract.getConfereeInfo(shareIndex,confereeIndex).send();
                ConfereeInfo conferee = new ConfereeInfo();

                conferee.setConfereeAdd(confereeInfo.get(0).getValue().toString());
                conferee.setScore(new BigInteger(confereeInfo.get(1).getValue().toString()).divide(Convert.Unit.ETHER.getWeiFactor().toBigInteger()).intValue());
                conferee.setTime(Integer.parseInt(confereeInfo.get(2).getValue().toString()));
                conferees.add(conferee);
            }

            Collections.reverse(conferees);
            return conferees;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void raiseShare(String desc) {
        contract.raiseShare(desc).sendAsync();
    }

    @Override
    public void gradeShare(int index, int score) {
        contract.gradeShare(index,score).sendAsync();
    }
}
